﻿using SocketCore.Common.Config;
using SocketCore.Common.Event;
using SocketCore.Common.Heartbeat;
using SocketCore.Common.Message;
using System.Net;
using System.Net.Sockets;

namespace SocketCore.Client;

public class ClientManager
{
    /// <summary>
    /// 客户端Socket
    /// </summary>
    private Socket _clientSocket;

    /// <summary>
    /// 客户端取消令牌
    /// </summary>
    private CancellationTokenSource _cancellationTokenSource;

    /// <summary>
    /// 是否连接
    /// </summary>
    public bool IsConnected => _clientSocket?.Connected == true;

    /// <summary>
    /// 心跳检测
    /// </summary>
    private readonly HeartbeatManager _heartbeatManager;

    /// <summary>
    /// 消息管理
    /// </summary>
    private readonly MessageManager _messageManager;

    /// <summary>
    /// 是否重连
    /// </summary>
    private bool _isReconnecting = false;

    /// <summary>
    /// 重连次数
    /// </summary>
    private int _reconnectAttempts = 0;

    /// <summary>
    /// 客户端配置
    /// </summary>
    private readonly ClientConfig _clientConfig;

    /// <summary>
    /// 构造
    /// </summary>
    public ClientManager(ClientConfig clientConfig)
    {
        _clientConfig = clientConfig ?? new ClientConfig();
        _messageManager = new MessageManager(_clientConfig, false);
        _heartbeatManager = new HeartbeatManager(_clientConfig, false);
        _clientConfig.EventHub.HeartbeatTimeout += OnHeartbeatTimeout;
        _clientConfig.EventHub.SendHeartbeatCallback = SendHeartbeatCallback;
    }

    /// <summary>
    /// 连接服务端
    /// </summary>
    /// <param name="ipAddress"></param>
    /// <param name="port"></param>
    /// <returns></returns>
    public async Task ConnectAsync()
    {
        _cancellationTokenSource = new CancellationTokenSource();

        try
        {
            // 创建客户端Socket
            _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // 启用TCP KeepAlive
            _heartbeatManager.SetSocketKeepAlive(_clientSocket, true, 60000, 10000);

            // 异步连接服务器
            await _clientSocket.ConnectAsync(_clientConfig.IPAddress, _clientConfig.Port);

            _clientConfig.EventHub.RaiseEvent(SocketEventType.Connect, new SocketClientConnect { ClientInfo = _clientSocket.RemoteEndPoint.ToString(), IsConnect = true });

            // 设置连接丢失回调
            _clientConfig.EventHub.ConnectionLost = OnConnectionLost;

            // 重置重连计数器
            _reconnectAttempts = 0;

            // 如果是重连成功，触发事件
            if (_isReconnecting)
            {
                _isReconnecting = false;
                _clientConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage { Level = LogLevel.Info, Message = $"已重新连接到服务端[{_clientConfig.IPAddress}:{_clientConfig.Port}]" });
            }
            else
            {
                _clientConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage { Level = LogLevel.Info, Message = $"已连接到服务端[{_clientConfig.IPAddress}:{_clientConfig.Port}]" });
            }
            await SendAsync(new MessageData<ClientVersionMessage> { MessageDataType = MessageDataType.ClientVersion, Data = new() { Version = _clientConfig.Version, HostName = Dns.GetHostName() } }.Serialize());

            // 启动心跳检测
            _heartbeatManager.StartHeartbeatCheck();

            // 初始化客户端心跳状态
            var clientState = new ClientHeartbeatState
            {
                ReceiveCts = new CancellationTokenSource()
            };

            if (_heartbeatManager.ClientStates.TryAdd(_clientSocket, clientState))
            {
                // 启动心跳发送任务
                _ = Task.Run(() => _heartbeatManager.SendHeartbeatsAsync(_clientSocket, _cancellationTokenSource.Token), _cancellationTokenSource.Token);

                // 启动接收任务
                _ = Task.Run(() => _messageManager.ReceiveMessagesAsync(_clientSocket, clientState, clientState.ReceiveCts.Token), clientState.ReceiveCts.Token);
            }
        }
        catch (Exception ex)
        {
            _clientConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage { Level = LogLevel.Error, Message = $"连接到服务端[{_clientConfig.IPAddress}:{_clientConfig.Port}]时发生错误：{ex.Message}", Exception = ex });
            _clientConfig.EventHub.RaiseEvent(SocketEventType.Connect, new SocketClientConnect { ClientInfo = string.Empty, IsConnect = false });
            // 如果不是主动断开连接，尝试重连
            if (!_cancellationTokenSource.IsCancellationRequested)
            {
                await AttemptReconnectAsync();
            }
            else
            {
                throw;
            }
        }
    }

    /// <summary>
    /// 连接丢失处理
    /// </summary>
    private void OnConnectionLost()
    {
        if (!_cancellationTokenSource.IsCancellationRequested)
        {
            _clientConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage
            {
                Level = LogLevel.Warning,
                Message = "检测到连接丢失，尝试重新连接..."
            });

            // 启动重连过程
            _ = AttemptReconnectAsync();
        }
    }

    /// <summary>
    /// 健康监测超时事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="socket"></param>
    private void OnHeartbeatTimeout(object? sender, Socket socket)
    {
        if (socket == _clientSocket && !_cancellationTokenSource.IsCancellationRequested)
        {
            _clientConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage
            {
                Level = LogLevel.Warning,
                Message = "检测到心跳超时，尝试重新连接..."
            });

            // 启动重连过程
            _ = AttemptReconnectAsync();
        }
    }

    /// <summary>
    /// 发送心跳检测回调方法
    /// </summary>
    /// <param name="socket"></param>
    /// <param name="cancellationToken"></param>
    private async void SendHeartbeatCallback(Socket socket, CancellationToken cancellationToken)
    {
        await _messageManager.SendAsync(socket, MessageProtocol.Message.CreateHeartbeat(), cancellationToken);
    }

    /// <summary>
    /// 重连
    /// </summary>
    /// <returns></returns>
    private async Task AttemptReconnectAsync()
    {
        if (_isReconnecting)
            return;

        _isReconnecting = true;

        // 清理旧连接
        CleanupOldConnection();
        var maxReconnectAttempts = _clientConfig.MaxReconnectAttempts ?? (_reconnectAttempts + 1);
        while (_reconnectAttempts < maxReconnectAttempts && !_cancellationTokenSource.IsCancellationRequested)
        {
            _reconnectAttempts++;
            if (!_clientConfig.MaxReconnectAttempts.HasValue)
                maxReconnectAttempts = _reconnectAttempts + 1;

            _clientConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage
            {
                Level = LogLevel.Info,
                Message = $"尝试重新连接 ({_reconnectAttempts}/{(_clientConfig.MaxReconnectAttempts.HasValue ? maxReconnectAttempts.ToString() : "Max")})..."
            });

            try
            {
                // 等待一段时间后尝试重连
                await Task.Delay(_clientConfig.ReconnectDelayMs, _cancellationTokenSource.Token);

                // 尝试重新连接
                await ConnectAsync();

                // 如果连接成功，退出循环
                if (IsConnected)
                {
                    break;
                }
                else if (_reconnectAttempts >= maxReconnectAttempts)
                {
                    _clientConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage
                    {
                        Level = LogLevel.Error,
                        Message = $"已达到最大重连次数({maxReconnectAttempts})，停止重连"
                    });
                }
            }
            catch (OperationCanceledException)
            {
                // 重连被取消，正常退出
                _clientConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage
                {
                    Level = LogLevel.Info,
                    Message = "重连过程被取消"
                });
                break;
            }
            catch (Exception ex)
            {
                _clientConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage
                {
                    Level = LogLevel.Error,
                    Message = $"第{_reconnectAttempts}次重连尝试失败: {ex.Message}"
                });

                // 如果是最后一次尝试，触发失败事件
                if (_reconnectAttempts >= maxReconnectAttempts)
                {
                    _clientConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage
                    {
                        Level = LogLevel.Error,
                        Message = $"已达到最大重连次数({maxReconnectAttempts})，停止重连"
                    });
                }
            }
        }

        _isReconnecting = false;
    }

    /// <summary>
    /// 清理旧连接
    /// </summary>
    private void CleanupOldConnection()
    {
        try
        {
            if (_clientSocket != null)
            {
                _heartbeatManager.RemoveClient(_clientSocket);
                _clientSocket?.Close();
                _clientSocket?.Dispose();
                _clientSocket = null;
            }

            // 重新创建CancellationTokenSource
            if (_cancellationTokenSource != null)
            {
                _cancellationTokenSource.Cancel();
                _cancellationTokenSource.Dispose();
            }
            _cancellationTokenSource = new CancellationTokenSource();
        }
        catch (Exception ex)
        {
            _clientConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage
            {
                Level = LogLevel.Warning,
                Message = $"清理旧连接时发生错误: {ex.Message}"
            });
        }
    }

    /// <summary>
    /// 发送消息
    /// </summary>
    /// <param name="message"></param>
    /// <returns></returns>
    public async Task SendAsync(string message)
    {
        await _messageManager.SendAsync(_clientSocket, MessageProtocol.Message.CreateText(message));
    }

    /// <summary>
    /// 手动触发重连
    /// </summary>
    /// <returns></returns>
    public async Task ReconnectAsync()
    {
        if (IsConnected)
        {
            Disconnect();
        }

        _reconnectAttempts = 0;
        await AttemptReconnectAsync();
    }

    /// <summary>
    /// 断开连接
    /// </summary>
    public void Disconnect()
    {
        _cancellationTokenSource?.Cancel();
        _heartbeatManager.Dispose(); // 确保心跳管理器也被清理
        try
        {
            _clientSocket?.Shutdown(SocketShutdown.Both);
            _clientSocket?.Close();
        }
        catch
        {
            // 忽略关闭时的异常
        }
        _clientConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage { Level = LogLevel.Info, Message = "客户端已停止" });
    }
}